﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SimpleX.Tracing
{
    public class TracingMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ITraceIdManager _traceIdManager;
        private readonly ILogger<TracingMiddleware> _logger;

        public TracingMiddleware(
            RequestDelegate next,
            ITraceIdManager traceIdManager,
            ILogger<TracingMiddleware> logger)
        {
            _next = next;
            _traceIdManager = traceIdManager;
            _logger = logger;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            // 从请求头中获取 TraceId 或生成新的 TraceId
            string traceId = context.Request.Headers["X-TraceId"].FirstOrDefault();

            if (string.IsNullOrEmpty(traceId))
            {
                traceId = _traceIdManager.GenerateNewTraceId();
            }

            // 设置 TraceId 到当前请求上下文
            _traceIdManager.SetTraceId(traceId);

            // 添加 TraceId 到响应头，便于前端追踪
            context.Response.Headers.Append("X-TraceId", traceId);

            // 创建请求活动
            using var activity = new Activity("HttpHandler").Start();
            activity?.SetTag("http.method", context.Request.Method);
            activity?.SetTag("http.path", context.Request.Path);
            activity?.SetTag("traceId", traceId);

            // 记录请求开始
            _logger.LogInformation("Request started [TraceId: {TraceId}]", traceId);

            var stopwatch = System.Diagnostics.Stopwatch.StartNew();

            try
            {
                // 继续处理请求
                await _next(context);
            }
            catch (Exception ex)
            {
                // 记录异常
                _logger.LogError(ex, "Request failed [TraceId: {TraceId}]", traceId);
                throw;
            }
            finally
            {
                stopwatch.Stop();

                // 记录请求完成
                _logger.LogInformation("Request completed in {ElapsedMilliseconds}ms [TraceId: {TraceId}]",
                    stopwatch.ElapsedMilliseconds,
                    traceId);
            }
        }
    }
}
